<script setup lang="ts">
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'
import {
  AxesHelper,
  Scene,
  PerspectiveCamera,
  WebGLRenderer,
  BoxGeometry,
  MeshBasicMaterial,
  Mesh,
  Raycaster,
  Vector2,
} from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GUI } from 'dat.gui'
import Stats from 'three/examples/jsm/libs/stats.module'

const contentRef = ref<HTMLCanvasElement>()
const renderer = shallowRef<WebGLRenderer>(new WebGLRenderer())
const orbitControls = shallowRef<OrbitControls>()
const scene = new Scene()
const camera = shallowRef<PerspectiveCamera>()
const axesHelper = new AxesHelper(20)
// 创建性能监视器
let stats = new Stats()
const meshList: Mesh[] = []
const whiteMaterial = new MeshBasicMaterial({ wireframe: true })
const redMaterial = new MeshBasicMaterial({ color: 'red' })

const gui = new GUI()
const raycaster = new Raycaster()
const pointer = new Vector2()

const init = () => {
  if (contentRef.value) {
    camera.value = new PerspectiveCamera(75, contentRef.value.clientWidth / contentRef.value.clientHeight)
    camera.value.position.set(0, 10, 20)
    scene.add(camera.value)
    scene.add(axesHelper)
    contentRef.value.appendChild(renderer.value.domElement)

    stats.dom.style.position = 'absolute'
    stats.dom.style.top = '0'
    stats.dom.style.left = '0'
    contentRef.value.appendChild(stats.dom)

    renderer.value.setSize(contentRef.value?.clientWidth, contentRef.value?.clientHeight)

    orbitControls.value = new OrbitControls(camera.value, renderer.value.domElement)
    orbitControls.value.enableDamping = true

    contentRef.value.addEventListener('mousemove', (e) => {
      if (contentRef.value) {
        const boundingClientRect = contentRef.value.getBoundingClientRect()
        pointer.x = ((e.clientX - boundingClientRect.left) / boundingClientRect.width) * 2 - 1
        pointer.y = -(((e.clientY - boundingClientRect.top) / boundingClientRect.height) * 2 - 1)
      }
    })
  }
}

const render = () => {
  if (camera.value) {
    orbitControls.value?.update()
    renderer.value?.render(scene, camera.value)
    raycaster.setFromCamera(pointer, camera.value)
    const intersect = raycaster.intersectObjects(meshList)
    if (intersect.length > 0) {
      if (intersect[0].object instanceof Mesh) {
        intersect[0].object.material = redMaterial
      }
    }
  }
  stats.update()
  requestAnimationFrame(render)
}

window.addEventListener('resize', () => {
  if (contentRef.value && camera.value) {
    camera.value.aspect = contentRef.value.clientWidth / contentRef.value.clientHeight
    camera.value.updateProjectionMatrix()

    renderer.value.setSize(contentRef.value?.clientWidth, contentRef.value?.clientHeight)
    renderer.value.setPixelRatio(window.devicePixelRatio)
  }
})

onMounted(() => {
  init()

  const boxGeometry = new BoxGeometry(1, 1, 1)

  for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
      for (let k = 0; k < 10; k++) {
        const mesh = new Mesh(boxGeometry, whiteMaterial)
        mesh.position.set(i, j, k)
        scene.add(mesh)
        meshList.push(mesh)
      }
    }
  }

  const guiAction = {}

  render()
})

onUnmounted(() => {
  gui.destroy()
})
</script>

<template>
  <div class="select-goods" ref="contentRef"></div>
</template>

<style lang="scss" scoped>
.select-goods {
  width: 100%;
  height: 100%;
  position: relative;
}
</style>
